package com.alibaba.citrus.ots.platform.enhance.facade.service.diff.sap;

import com.alibaba.acm.shaded.com.google.common.collect.Lists;
import com.alibaba.citrus.common.pair.Pair;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.DiffCheckRequest;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.constant.DiffResultStatus;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.constant.DiffTypeEnum;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.constant.DiffStrategyRouteDict;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.dataParser.DataParserManager;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.router.DiffCheckProcessor;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.router.DiffStrategyRoute;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.template.StandardTemplateDiff;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.sap.template.SalesOrderLineSap015StandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.sap.template.SalesOrderSap015StandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.sap.template.Sap015SDODetailStandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.sap.template.Sap015SDOStandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.repository.DiffErrorRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.SalesOrderLineQueryServiceRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.SalesOrderQueryServiceRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.DiffErrorDTO;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.FieldLineDTO;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.SalesOrderDTO;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.SalesOrderLineDTO;
import com.alibaba.citrus.trail.log.LogEntry;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.alibaba.nacos.common.utils.MapUtils;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015Detail;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015Request;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf015SDO;
import com.epoch.app.otsplatformenhance.model.dto.Sap015DiffRequest;
import com.epoch.app.otsplatformenhance.sap015diffcheck.dto.DiffCheckBySapDataRequest;
import com.epoch.app.otsplatformenhance.sap015diffcheck.service.Sap015DiffCheckService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author hanguo
 * @date 2022/1/23
 * @Description 请填写描述信息
 */
@Primary
@Service
public class Sap015DiffCheckServiceImpl extends AbstractDiffCheck implements Sap015DiffCheckService {


    private Log log = Log.getLogger(Sap015DiffCheckServiceImpl.class);


    /**
     * 标准对账模板
     */
    @Resource
    private StandardTemplateDiff standardTemplateDiff;

    /**
     * 数据解析器管理类
     */
    @Resource
    private DataParserManager dataParserManager;

    /**
     * 对账策略路由
     */
    @Resource
    private DiffStrategyRoute diffStrategyRoute;

    /**
     * 差错资源类
     */
    @Resource
    private DiffErrorRepository diffErrorRepository;


    @Resource
    private SalesOrderQueryServiceRepository salesOrderQueryServiceRepository;

    @Resource
    private SalesOrderLineQueryServiceRepository salesOrderLineQueryServiceRepository;

    @Override
    @FacadeInvoker
    public Result<String> diffCheck(Sap015DiffRequest sap015DiffRequest) {
        checkParam(sap015DiffRequest);

        super.doTraverse(sap015DiffRequest.getCondition(),sap015DiffRequest.getStartDate(),
                sap015DiffRequest.getEndDate());
        return Result.success("ture");
    }

    @Override
    void doHandlerLog(Pair<Integer, List<LogEntry>> pair) {
        List<DiffErrorDTO> diffErrorDTOList = new ArrayList<>();
        pair.right().forEach(logEntry -> {
            if (MapUtils.isNotEmpty(logEntry.contents())) {
                String sapMsg = logEntry.contents().get("input");
                log.info("sapMsg={}", sapMsg);
                JSONObject jsonObject = JSON.parseObject(sapMsg);
                String data = jsonObject.getString("body").trim();
                log.info("data={}", data);
                MnSapIf015Request sapIf015Request = JSON.parseObject(data, MnSapIf015Request.class);
                MnSapIf015SDO sapIf015SDO = sapIf015Request.getData();
                if (Objects.nonNull(sapIf015SDO)) {
                    List<DiffErrorDTO> diffErrorDTOList1 = sap015Diff(sapIf015SDO);
                    if (Objects.nonNull(diffErrorDTOList1)) {
                        diffErrorDTOList.addAll(diffErrorDTOList1);
                    }
                }
            }
        });
        if (CollectionUtils.isNotEmpty(diffErrorDTOList)) {
            diffErrorRepository.batchSaveDiffErrorList(diffErrorDTOList);
        }
    }

    /**
     * sap015 对账
     *
     * @param sapIf015SDO SAP015 数据
     * @return
     */
    public List<DiffErrorDTO> sap015Diff(MnSapIf015SDO sapIf015SDO) {

        List<DiffErrorDTO> diffErrorDTOList = Lists.newArrayList();
        try {
            //1. 数据抽取
            Map<String, FieldLineDTO> sapIf015SDOMap = dataParserManager.parse(sapIf015SDO);
            //2. 和标准模板进行对比，检查是否缺的问题。 缺失有两个问题： a. 字段缺失， b. 数值缺失
            standardTemplateDiff.check(Sap015SDOStandardTemplate.obtainTemplateFieldSet(),
                    sapIf015SDOMap, Sap015SDOStandardTemplate.obtainIgnoreFieldSet());

            //3. 获取销售主单
            //获取DB中的销售主单
            String tradeOrderId = sapIf015SDO.getTradeOrderId();
            SalesOrderDTO salesOrderDTO = salesOrderQueryServiceRepository.queryById(tradeOrderId);
            if (Objects.isNull(salesOrderDTO)) {
                log.error("未查询到销售主单");
                DiffErrorDTO diffErrorDto = buildSap015SDODiffErrorDTO(sapIf015SDO, sapIf015SDOMap,
                        null, "未查询到ots侧销售主单信息");
                diffErrorDTOList.add(diffErrorDto);
                return diffErrorDTOList;

            }
            //4. 从销售主单上抽取数据
            Map<String, FieldLineDTO> salesOrderDataMap = dataParserManager.parse(salesOrderDTO);
            //5. 和标准模板进行对比，检查是否缺的问题。
            Result<String> checkResult = standardTemplateDiff.check(SalesOrderSap015StandardTemplate.obtainTemplateFieldSet(), salesOrderDataMap,
                    SalesOrderSap015StandardTemplate.obtainIgnoreFieldSet());
            if (!checkResult.isSuccess()) {
                //埋点
                log.error("Sap015DiffCheckServiceImpl#sap015DiffCheck_fail");
                DiffErrorDTO diffErrorDTO = buildSap015SDODiffErrorDTO(sapIf015SDO, sapIf015SDOMap,
                        salesOrderDataMap, checkResult.getMessage());
                diffErrorDTOList.add(diffErrorDTO);
                return diffErrorDTOList;
            }

            //6. 对账
            DiffCheckRequest diffCheckRequest = buildSaleOrderDiffCheckRequest(sapIf015SDOMap, salesOrderDataMap);
            DiffCheckProcessor diffCheckProcessor = diffStrategyRoute.obtainProcessor(diffCheckRequest);
            Result<String> diffResult = diffCheckProcessor.diff(diffCheckRequest);
            if (!diffResult.isSuccess()) {
                //埋点
                log.error("Sap015DiffCheckServiceImpl#sap015DiffCheck_fail");
                DiffErrorDTO diffErrorDto = buildSap015SDODiffErrorDTO(sapIf015SDO, sapIf015SDOMap,
                        salesOrderDataMap, diffResult.getMessage());
                diffErrorDTOList.add(diffErrorDto);
            }

            List<MnSapIf015Detail> sapIf015DetailList = sapIf015SDO.getItems();
            if (CollectionUtils.isNotEmpty(sapIf015DetailList)) {
                //sap销售子单对账
                List<DiffErrorDTO> subDiffErrorDto = sap015DetailDiffCheck(sapIf015DetailList, sapIf015SDO.getTradeOrderId());
                if (CollectionUtils.isNotEmpty(subDiffErrorDto)) {
                    diffErrorDTOList.addAll(subDiffErrorDto);
                }
            }
        } catch (Exception e) {
            //埋点
            log.error("Sap015DiffCheckServiceImpl#sap015DiffCheck_fail");
            log.error("sap015主单对账出错了", e);
            DiffErrorDTO diffErrorDto = buildSap015SDODiffErrorDTO(sapIf015SDO, null,
                    null, "对账出异常了！");
            diffErrorDTOList.add(diffErrorDto);
        }
        return diffErrorDTOList;
    }

    /**
     * 构建销售子单对账路由
     *
     * @param sapIf015SDOMap
     * @param salesOrderDataMap
     * @return
     */
    @NotNull
    private DiffCheckRequest buildSaleOrderDiffCheckRequest(Map<String, FieldLineDTO> sapIf015SDOMap, Map<String, FieldLineDTO> salesOrderDataMap) {
        DiffCheckRequest diffCheckRequest = new DiffCheckRequest();
        diffCheckRequest.setStrategyRoute(DiffStrategyRouteDict.SAP015SDO_DIFF_SALES_ORDER.getStrategyCode());
        diffCheckRequest.setDiffDesc(DiffTypeEnum.SAP_IF_015_SALES_ORDER.getDiffDesc());
        diffCheckRequest.setBaseLineDataMap(sapIf015SDOMap);
        diffCheckRequest.setDiffDataMap(salesOrderDataMap);
        diffCheckRequest.setDiffType(DiffTypeEnum.SAP_IF_015_SALES_ORDER.getDiffType());
        return diffCheckRequest;
    }

    /**
     * 构建销售子单对账路由
     *
     * @param sapIf015SDODetailMap
     * @param salesOrderLineDataMap
     * @return
     */
    @NotNull
    private DiffCheckRequest buildSaleOrderLineDiffCheckRequest(Map<String, FieldLineDTO> sapIf015SDODetailMap, Map<String, FieldLineDTO> salesOrderLineDataMap) {
        DiffCheckRequest diffCheckRequest = new DiffCheckRequest();
        diffCheckRequest.setStrategyRoute(DiffStrategyRouteDict.SAP015DETAIL_DIFF_SALES_ORDER_LINE.getStrategyCode());
        diffCheckRequest.setDiffDesc(DiffTypeEnum.SAP_IF_015_SALES_ORDER_LINE.getDiffDesc());
        diffCheckRequest.setBaseLineDataMap(sapIf015SDODetailMap);
        diffCheckRequest.setDiffDataMap(salesOrderLineDataMap);
        diffCheckRequest.setDiffType(DiffTypeEnum.SAP_IF_015_SALES_ORDER_LINE.getDiffType());
        return diffCheckRequest;
    }

    /**
     * 构造差错 DTO
     *
     * @param sapIf015SDO       sap015对账数据
     * @param sapIf015SDOMap
     * @param salesOrderDataMap
     * @param diffResult        对账结果信息
     * @return 对账信息
     */
    private DiffErrorDTO buildSap015SDODiffErrorDTO(MnSapIf015SDO sapIf015SDO,
                                                    Map<String, FieldLineDTO> sapIf015SDOMap,
                                                    Map<String, FieldLineDTO> salesOrderDataMap, String diffResult) {
        //1. 封装差错记录
        DiffErrorDTO diffErrorDto = DiffErrorDTO.builder()
                .diffType(DiffTypeEnum.SAP_IF_015_SALES_ORDER.getDiffType())
                //业务流程描述
                .diffDesc(DiffTypeEnum.SAP_IF_015_SALES_ORDER.getDiffDesc())
                //对账结果描述
                .result(diffResult)
                .diffData1(JSON.toJSONString(sapIf015SDOMap))
                .diffData2(JSON.toJSONString(salesOrderDataMap))
                .strategyRoute(DiffStrategyRouteDict.SAP015SDO_DIFF_SALES_ORDER.getStrategyCode())
                .mainOrderId(sapIf015SDO.getTradeOrderId())
                //.subOrderId(sapIf015SDO.getSubOrderId())
                //.activityId(sapIf015SDO.getActivityId())
                //.activityTermId(sapIf015SDO.getActivityTermId())
                //.sequence(sapIf015SDO.getSequenceNo())
                .status(DiffResultStatus.FAIL.getStatus()).build();
        return diffErrorDto;
    }

    /**
     * 构造差错 DTO
     *
     * @param mnSapIf015Detail      sap015对账数据
     * @param sapIf015DetailMap
     * @param salesOrderLineDataMap
     * @param diffResult            对账结果信息
     * @return 对账信息
     */
    private DiffErrorDTO buildSap015SDODetailDiffErrorDTO(MnSapIf015Detail mnSapIf015Detail,
                                                          Map<String, FieldLineDTO> sapIf015DetailMap,
                                                          Map<String, FieldLineDTO> salesOrderLineDataMap, String diffResult) {
        //1. 封装差错记录
        DiffErrorDTO diffErrorDto = DiffErrorDTO.builder()
                .diffType(DiffTypeEnum.SAP_IF_015_SALES_ORDER_LINE.getDiffType())
                //业务流程描述
                .diffDesc(DiffTypeEnum.SAP_IF_015_SALES_ORDER_LINE.getDiffDesc())
                //对账结果描述
                .result(diffResult)
                .diffData1(JSON.toJSONString(sapIf015DetailMap))
                .diffData2(JSON.toJSONString(salesOrderLineDataMap))
                .strategyRoute(DiffStrategyRouteDict.SAP015DETAIL_DIFF_SALES_ORDER_LINE.getStrategyCode())
                //.mainOrderId(mnSapIf015Detail.getOrderLineId())
                .subOrderId(mnSapIf015Detail.getOrderLineId())
                //.activityId(sapIf015SDO.getActivityId())
                //.activityTermId(sapIf015SDO.getActivityTermId())
                //.sequence(sapIf015SDO.getSequenceNo())
                .status(DiffResultStatus.FAIL.getStatus()).build();
        return diffErrorDto;
    }


    /**
     * sap销售子单对账
     *
     * @param sapIf015DetailList
     * @param mainOrderId
     * @return
     */
    private List<DiffErrorDTO> sap015DetailDiffCheck(List<MnSapIf015Detail> sapIf015DetailList, String mainOrderId) {

       List<DiffErrorDTO> diffErrorDTOList = Lists.newArrayList();
        //获取DB中的所有销售子单
        //1.获取sap中的销售子单ids
        //2.根据子单ids批量查询DB,转为map
        //3.遍历sap销售子单和DB的数据做比对


        //查询DB
        List<SalesOrderLineDTO> salesOrderLineDTOS = salesOrderLineQueryServiceRepository.querySalesOrderLineByOrderId(mainOrderId);

        //根据订单行号进行分组
        Map<String, SalesOrderLineDTO> salesOrderLineDTOMap = salesOrderLineDTOS.stream().collect(Collectors.toMap(SalesOrderLineDTO::getSerialNumber, Function.identity()));

//        Map<Long, SalesOrderLineDTO> salesOrderLineDTOMap = salesOrderLineDTOS.stream().collect(Collectors.toMap(SalesOrderLineDTO::getId, Function.identity()));

        for (MnSapIf015Detail mnSapIf015Detail : sapIf015DetailList) {

            try {
                //1. 数据抽取
                Map<String, FieldLineDTO> sapIf015DetailMap = dataParserManager.parse(mnSapIf015Detail);
                //2. 和标准模板进行对比，检查是否缺的问题。 缺失有两个问题： a. 字段缺失， b. 数值缺失
                standardTemplateDiff.check(Sap015SDODetailStandardTemplate.obtainTemplateFieldSet(),
                        sapIf015DetailMap, Sap015SDODetailStandardTemplate.obtainIgnoreFieldSet());

                //1.获取DB中的销售子单数据
                SalesOrderLineDTO salesOrderLineDTO = salesOrderLineDTOMap.get(mnSapIf015Detail.getOrderLineId());
//                if (Objects.isNull(salesOrderLineDTO)) {
//                    log.error("未查询到销售子单");
//                    throw new ProcessException("OTS-13-001-00-16-010");
//                }

                //3. 从销售子单上抽取数据
                Map<String, FieldLineDTO> salesOrderLineDataMap = dataParserManager.parse(salesOrderLineDTO);
                //4. 和标准模板进行对比，检查是否缺的问题。
                Result<String> checkResult = standardTemplateDiff.check(SalesOrderLineSap015StandardTemplate.obtainTemplateFieldSet(), salesOrderLineDataMap,
                        SalesOrderLineSap015StandardTemplate.obtainIgnoreFieldSet());
                if (!checkResult.isSuccess()) {
                    log.error("Sap015DiffCheckServiceImpl#sap015DetailDiffCheck_fail");
                    DiffErrorDTO diffErrorDTO = buildSap015SDODetailDiffErrorDTO(mnSapIf015Detail, sapIf015DetailMap,
                            salesOrderLineDataMap, checkResult.getMessage());
                    diffErrorDTOList.add(diffErrorDTO);
                    continue;
                }

                //6. 对账
                DiffCheckRequest diffCheckRequest = buildSaleOrderLineDiffCheckRequest(sapIf015DetailMap, salesOrderLineDataMap);
                DiffCheckProcessor diffCheckProcessor = diffStrategyRoute.obtainProcessor(diffCheckRequest);
                Result<String> diffResult = diffCheckProcessor.diff(diffCheckRequest);
                if (!diffResult.isSuccess()) {
                    //埋点
                    log.error("Sap015DiffCheckServiceImpl#sap015DetailDiffCheck_fail");
                    DiffErrorDTO diffErrorDto = buildSap015SDODetailDiffErrorDTO(mnSapIf015Detail, sapIf015DetailMap,
                            salesOrderLineDataMap, diffResult.getMessage());
                    diffErrorDTOList.add(diffErrorDto);
                }
            } catch (Exception e) {
                //埋点
                log.error("Sap015DiffCheckServiceImpl#sap015DetailDiffCheck_fail");
                log.error("sap015子单对账出错了", e);
                DiffErrorDTO diffErrorDto = buildSap015SDODetailDiffErrorDTO(mnSapIf015Detail, null,
                        null, "对账出异常了！");
                diffErrorDTOList.add(diffErrorDto);
            }

        }


        return diffErrorDTOList;
    }


    @Override
    @FacadeInvoker
    public Result<String> diffCheckBySapData(DiffCheckBySapDataRequest diffCheckBySapDataRequest) {
        String sap015Data = diffCheckBySapDataRequest.getSap015JsonData();
        MnSapIf015SDO sapIf015SDO = JSON.parseObject(sap015Data, MnSapIf015SDO.class);
        List<DiffErrorDTO> diffErrorDTOList = sap015Diff(sapIf015SDO);
        if (CollectionUtils.isNotEmpty(diffErrorDTOList)) {
            return Result.success("数据一致");
        } else {
            return Result.fail("", JSON.toJSONString(diffErrorDTOList));
        }
    }


    /**
     * 校验参数
     *
     * @param sap015DiffRequest SAP 015请求
     */
    private void checkParam(Sap015DiffRequest sap015DiffRequest) {
        if (Objects.isNull(sap015DiffRequest)) {
            throw new FacadeException("OTS-13-001-00-16-003");
        }

        if (Objects.isNull(sap015DiffRequest.getStartDate())) {
            throw new FacadeException("OTS-13-001-00-16-004");
        }

        if (Objects.isNull(sap015DiffRequest.getEndDate())) {
            throw new FacadeException("OTS-13-001-00-16-005");
        }

        if (StringUtils.isBlank(sap015DiffRequest.getCondition())) {
            throw new FacadeException("OTS-13-001-00-16-013");
        }
    }
}
